<?php

namespace App\Console\Commands;

use App\Enum\LogsEnum;
use App\Enum\OrderDyplsEnum;
use App\Enum\OrderEnum;
use App\Lib\DyplsapiClient;
use App\Models\LogsModel;
use App\Models\OrderDyplsModel;
use App\Models\OrderExtendModel;
use App\Models\OrderModel;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class orderDyplsCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'order:dypls {num_per_each?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '虚拟号码的绑定与解绑';

    private $dyplsClient = null;
    private static $pools = [
        ['pool_key'=>'FC100000175174106','phone_x'=>'17177789578','num'=>200]
        ,['pool_key'=>'FC100000175174106','phone_x'=>'17177787466','num'=>200]
        ,['pool_key'=>'FC100000175174106','phone_x'=>'17177785847','num'=>200]
        ,['pool_key'=>'FC100000175174106','phone_x'=>'17132116933','num'=>200]
        ,['pool_key'=>'FC100000175174106','phone_x'=>'17177785272','num'=>200]
        ];

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->dyplsClient = DyplsapiClient::createClient();
    }


    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        if( env('ALIYUN_DYPLS_ENABLED',true) === false ){
            $this->info('aliyun dypls disabled');
            return true;
        }
        $num = $this->argument('num_per_each') ?? 1;

        while(1) {
            $second = date('s');
            $sleepRatio = 1;
            $sleep = 1;

            if ($second >= 55) {
                $this->info("second = $second, wait for next time.");
                break;
            }else  $this->info("second = $second, keep going.");

            // 0.1 將超時的狀態改為 已經完結
            $this->changeDone();
            // 0.2 將poolKey和X更新到表中
            $this->setPoolKeyAndNoX();
            // 0.3 將error狀態的重新分配pool和x
            $this->reassignPool();

            // 1 解绑
            $this->_unBind($num);

            // 2 更新
            $this->_updateBind($num);
            // 3 绑定
            $this->_bind($num);

            sleep($sleep*$sleepRatio);
        }
        //
        return 0;
    }
    // 將error狀態的重新分配pool和x
    private function reassignPool(){
        $pools = [];
        foreach( self::$pools as $pool ) $pools[$pool['phone_x']] = $pool;

        $rows = OrderDyplsModel::query()->where('status', '=', OrderDyplsEnum::STATUS_BIND_ERROR)->get()->toArray();
        if( !empty($rows) ){
            foreach( $rows as $row ){

                $pool = $this->_getAvailPool($pools, $row['old_phone_x']);
                $this->info('reassignPool'.var_export($pool,true));
                if( empty($pool) ){
                    OrderDyplsModel::query()->where('id', '=', $row['id'])->update(['status'=>OrderDyplsEnum::STATUS_BIND_NONE]);
                }else{
                    OrderDyplsModel::query()->where('id', '=', $row['id'])->update(['status'=>OrderDyplsEnum::STATUS_BIND_TODO,'pool_key'=>$pool['pool_key'],'phone_x'=>$pool['phone_x'] ]);
                }
            }
        }
    }
    private function _getAvailPool( $pools, $oldPhoneX){
        $oldPhoneX = json_decode($oldPhoneX,true);
        foreach( $pools as $k=>$pool )if(in_array($k, $oldPhoneX))unset($pools[$k]);
        if( empty($pools) ) return false;
        return array_values($pools)[0];
    }
    // 將超時的狀態改為 已經完結
    private function changeDone(){
        OrderDyplsModel::query()->where('expiration','<',date('Y-m-d H:i:s'))->update(['status'=>OrderDyplsEnum::STATUS_BIND_DONE]);
    }

    private function setPoolKeyAndNoX(){
        $pools = [];
        foreach( self::$pools as $pool ) $pools[$pool['phone_x']] = $pool;

        $rows = OrderDyplsModel::query()->fromQuery("SELECT pool_key, phone_x, COUNT(*) AS num FROM `sxcx_order_dypls` WHERE pool_key IS NOT NULL AND `status` NOT IN (".OrderDyplsEnum::STATUS_BIND_DONE.") AND expiration > CURRENT_TIMESTAMP() GROUP BY pool_key, phone_x ")->toArray();
        if( !empty($rows) ){
            foreach( $rows as $row ){
                $pools[$row['phone_x']]['num'] -= $row['num'];
            }
        }
        // 如果存在TODO
        $res= DB::select("select 1 from sxcx_order_dypls where pool_key is null");
        if( !empty($res) )
        foreach( $pools as $pool ){
            $rows = DB::update("update `sxcx_order_dypls` set pool_key='".$pool['pool_key']."', phone_x='".$pool['phone_x']."' where pool_key is null and `status` =1 limit ".$pool['num']);
        }
    }
    // 绑定
    private function _bind($num){
        $rows = OrderDyplsModel::query()->where('status','=',OrderDyplsEnum::STATUS_BIND_TODO)->limit($num)->get()->toArray();
        if( !empty($rows) ){
            foreach($rows as $row ){
                $params = [];
                $params['poolKey']      = $row['pool_key'];
                $params['phoneNoA']       = $row['phone_a'];
                $params['phoneNoB']       = $row['phone_b'];
                $params['phoneNoX']     = $row['phone_x'];
                $params['expiration']   = $row['expiration'];
                $params['outId']        = $row['order_no'];
                $logContent = '绑定虚拟号：';
                $logMemo = '';


                try{
                    $result = DyplsapiClient::bindAxb($this->dyplsClient, $params);
                    $subsId = $result->body->secretBindDTO->subsId;
                    OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_BIND_SUCCESS,'subs_id'=>$subsId]);
                    $logContent .= '成功';
                    $logMemo = json_encode($result);
                    $this->info($row['order_no'].' => '. $subsId);
                } catch(\Exception $e){
                    $oldPhoneX = [];
                    if( !empty($row['old_phone_x']) )$oldPhoneX = json_decode($row['old_phone_x'],true);

                    $oldPhoneX[] = $row['phone_x'];
                    OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_BIND_ERROR,'old_phone_x'=>json_encode($oldPhoneX)]);
                    $logContent .= '失败';
                    $logMemo = $e->getMessage();
                    $this->error($e->getMessage());
                }
                $this->_addOrderLog(['order_id'=>$row['order_id'], 'order_no'=>$row['order_no']
                                    ,'content'=> $logContent, 'result' => $logMemo
                ]);

            }
        }
    }
    private function _addOrderLog($params){
        // 添加订单日志 20230901 by LC
        LogsModel::query()->create([
            'type'      => LogsEnum::LOGS_TYPE_ORDER,
            'ref_id'    => $params['order_id'],
            'ref_no'  => $params['order_no'],
            'user_id'   => 0,
            'user_type' => LogsEnum::LOGS_USER_TYPE_SYSTEM,
            'username'  => LogsEnum::LOGS_USER_NAME,
            'content' => $params['content'],
            'memo'  => $params['result']
        ]);
    }
    // 解绑
    private function _unBind($num){
        $rows = OrderDyplsModel::query()->where(['status'=>OrderDyplsEnum::STATUS_UNBIND_TODO])->limit($num)->get()->toArray();
        if( !empty($rows) ){
            foreach($rows as $row ){
                $logContent = '解绑虚拟号：';
                $logMemo = '';
                $subsId = $row['subs_id'];
                if( empty($subsId) ) OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_UNBIND_DONE]);
                else{
                    try {
                        $params = [];
                        $params['secretNo'] = $row['phone_x'];
                        $params['subsId'] = $row['subs_id'];
                        $params['poolKey'] = $row['pool_key'];
                        $result = DyplsapiClient::unbind($this->dyplsClient, $params);
                        $logContent .= "成功";
                        $logMemo = json_encode($result);
                        OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_UNBIND_DONE]);
                    }catch(\Exception $e){
                        OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_UNBIND_ERROR]);
                        $logContent .= "失败";
                        $logMemo = $e->getMessage();
                        $this->error($e->getMessage());
                    }
                }
                $this->_addOrderLog(['order_id'=>$row['order_id'], 'order_no'=>$row['order_no']
                    ,'content'=> $logContent, 'result' => $logMemo
                ]);
            }
        }
    }
    // 更新绑定关系

    /**
     * @param $num
     * @return void
     * "subsId" => $params['subsId'],
     * "phoneNoX" => $params['phoneNoX'],
     * "operateType" => $params['operateType']
     */
    private function _updateBind($num){
        $rows = OrderDyplsModel::query()->where(['status'=>OrderDyplsEnum::STATUS_BIND_UPDATE])->limit($num)->get()->toArray();
        if( !empty($rows) ){
            foreach($rows as $row ){
                $logContent = '更新绑定：';
                $params = [];
                $params['phoneNoX']     = $row['phone_x'];
                $params['subsId']       = $row['subs_id'];
                $params['operateType']  = 'updateNoA';
                $params['poolKey']      = $row['pool_key'];
                $params['phoneNoA']     = $row['phone_a'];

                try {
                    $result = DyplsapiClient::updateBind($this->dyplsClient, $params);
                    OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_BIND_SUCCESS,'subs_id'=>$row['subs_id']]);
                    $logContent .= "成功";
                    $logMemo = json_encode($result);
                }catch(\Exception $e){
                    $this->error($e->getMessage());
                    $logContent .= "失败";
                    $logMemo = $e->getMessage();
                    $oldPhoneX = is_null(json_decode($row['old_phone_x'],true))??[];
                    $oldPhoneX[] = $row['phone_x'];
                    OrderDyplsModel::query()->where(['id'=>$row['id']])->update(['status'=>OrderDyplsEnum::STATUS_BIND_ERROR,'old_phone_x'=>json_encode($oldPhoneX)]);
                }
                $this->_addOrderLog(['order_id'=>$row['order_id'], 'order_no'=>$row['order_no']
                    ,'content'=> $logContent, 'result' => $logMemo
                ]);
            }
        }
    }
}
